package com.hp.bon.sgw.wh.channel;

import java.io.IOException;
import java.io.PrintStream;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ThreadPoolExecutor;

import javax.xml.stream.XMLInputFactory;

import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.simpleframework.http.ContentType;
import org.simpleframework.http.Request;
import org.simpleframework.http.Response;
import org.simpleframework.http.core.Container;
import org.simpleframework.http.core.ContainerProcessor;
import org.simpleframework.http.core.ContainerSelector;
import org.simpleframework.http.core.ContainerServer;
import org.simpleframework.transport.connect.Connection;
import org.simpleframework.transport.connect.SocketConnection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hp.bon.sgw.Constants.NodeStatus;
import com.hp.bon.sgw.bean.XmlMessage;
import com.hp.bon.sgw.core.CallParam;
import com.hp.bon.sgw.core.channel.IChannel;
import com.hp.bon.sgw.domain.Node;
import com.hp.bon.sgw.domain.SGWChannel;
import com.hp.bon.sgw.service.ConfigListener;
import com.hp.bon.sgw.service.ConfigService;
import com.hp.bon.sgw.start.SpringContext;
import com.hp.bon.sgw.util.Comutils;
import com.hp.bon.sgw.wh.mml.VCClient;
import com.hp.bon.sgw.wh.mml.common.MMLConstants;
import com.hp.bon.sgw.wh.mml.common.MMLSessionEntity;
import com.hp.bon.sgw.wh.mml.common.MsgUtils;
import com.hp.bon.sgw.wh.mml.handler.HttpResponseHandler;
import com.hp.bon.sgw.wh.mml.handler.HttpTimeoutHandler;
import com.hp.bon.sgw.wh.mml.handler.MsgLogServerHandler;
import com.hp.bon.sgw.wh.mml.handler.VCMonitorHandler;
import com.hp.bon.sgw.wh.mml.helper.HttpAckHelper;
import com.hp.bon.sgw.wh.mml.helper.LogMsgHelper;
import com.hp.bon.sgw.wh.mml.helper.PropertiesHelper;
import com.hp.bon.sgw.wh.mml.parser.XmlMessageParser;
import com.hp.bon.sgw.wh.mml.repositories.PropertyRepository;
import com.hp.bon.sgw.wh.mml.repositories.VCMsgRepository;

/**
 * @author xiaofeng
 * 
 */
public class ZBVCChannel implements Container, ConfigListener, IChannel {
	
	private static final Logger logger = LoggerFactory.getLogger(ZBVCChannel.class);
	
	public static XMLInputFactory inputFactory = XMLInputFactory.newInstance();
	
	private ContainerServer server = null;
	private SGWChannel channel;
	protected ConfigService confSrv;
	private MultiThreadedHttpConnectionManager connectionManager;
	
	public ZBVCChannel(SGWChannel channel) {
		this.channel = channel;
		confSrv = SpringContext.getInstance().getConfigService();
	}
	
	ThreadPoolExecutor executor;
	ThreadPoolExecutor collector;
	
	@Override
	public void start() throws IOException {
		logger.info("start ZBVC channel:" + channel.toString() + " ...");
		
		logger.info("load ZBVC Properties...");
		PropertiesHelper.loadZBVCProperties();
		
		logger.info("setup VCClient...");
		if(!VCClient.instance().setupVCClient()){
			logger.warn("setup VCClient failed!!!");
			logger.warn("fail: start ZBVC channel. For VCClient.");
			return;			
		}
		
		String key = "sgw.zbvcchannel.thread.max";
		int maxThreads = confSrv.getIntValue(key, 20);
		logger.info(key + " :" + maxThreads);
		String endPoint = this.channel.getUri();
		if (endPoint == null) {
			logger.warn("channel dont't defined uri");
			return;
		}
		logger.info("start sgw ZBVCChannel server portal at " + endPoint);

		try {
			URL srvURL = new URL(endPoint);
			int port = srvURL.getPort();
			//找不到端口就启动失败
			if (port == -1) {
				logger.info("start ZBVCChannel error : port Not defined");
				return ;
			}
			String host = srvURL.getHost();
			if (host.equals("127.0.0.1") || host.equalsIgnoreCase("localhost")) {
				host = "0.0.0.0";
			}
			server = new ContainerServer(this, maxThreads);

			@SuppressWarnings("resource")
			Connection connection = new SocketConnection(server);
			SocketAddress address = new InetSocketAddress(host, port);
			connection.connect(address);
			collector = ((ContainerSelector) ((ContainerProcessor) server.getProcessor()).getSelector()).getCollect().getQueue();
			executor = ((ContainerSelector) ((ContainerProcessor) server.getProcessor()).getSelector()).getExecutor().getQueue();

			logger.info("start HttpResponseHandler...");
			HttpResponseHandler.startHandler();
			logger.info("start HttpTimeoutHandler...");
			HttpTimeoutHandler.startHandler();
			logger.info("start VCMonitorHandler...");
			VCMonitorHandler.startHandler();
			logger.info("start MsgLogServerHandler...");
			MsgLogServerHandler.startHandler();
			
			this.channel.setStatus(NodeStatus.ON_LINE);
			confSrv.updateChannelStatus2DB(this.channel.getId(),NodeStatus.ON_LINE);
		} catch (IOException e) {
			logger.error("start Taobao channel " + this.channel.toString()+ " err " + e);
		}
	}
	
	@Override
	public void stop() {
		logger.info("stop ZBVCChannel...");		

		logger.info("stop HttpResponseHandler...");
		HttpResponseHandler.stopHandler();
		logger.info("stop HttpTimeoutHandler...");
		HttpTimeoutHandler.stopHandler();
		logger.info("stop VCMonitorHandler...");
		VCMonitorHandler.stopHandler();
		logger.info("stop MsgLogServerHandler...");
		MsgLogServerHandler.stopHandler();
		
		//tear down vcClient
		logger.info("tear down vc client");
		VCClient.teardownVCClient();
		
		if (server != null) {
			try {
				server.stop();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		if (connectionManager != null) {
			connectionManager.shutdown();
		}

		this.channel.setStatus(NodeStatus.OFF_LINE);
		confSrv.updateChannelStatus2DB(this.channel.getId(),NodeStatus.OFF_LINE);
		
		try {
			logger.info("wait 3s to exit...");
			Thread.sleep(3*1000);
		} catch (InterruptedException e) {
			logger.warn("Thread.sleep InterruptedException:",e);
		}
	}
	
	/**
	 * 接收中百VC的HTTP请求 解析HTTP请求，将请求消息封装成XmlMessage
	 */
	@Override
	public void handle(Request request, Response response) {
		
		logger.info("receive request from " + request.getClientAddress() + "; "	+ request.toString());
		
		long receiveTime = System.currentTimeMillis();
		PrintStream bodyPrintStream = null;
		try {
			bodyPrintStream = response.getPrintStream();
			response.set("Content-Type", "text/xml;charset=utf-8");
			response.set("Server", "HP  Asyn WS WebServer )");
			response.setDate("Date", receiveTime);
			response.setDate("Last-Modified", receiveTime);
			ContentType cntType = request.getContentType();
			if (cntType == null) {
				bodyPrintStream.println("invalid request Content type is null");
				bodyPrintStream.close();
				return;
			}
			cntType.setCharset(Comutils.fixContentCharSet(cntType.getCharset()));
		} catch (IOException e1) {
			logger.warn("get response print stream error...");
			e1.printStackTrace();
			return;
		}
		
		String errInfos = null;
		XmlMessage xmlMsg = null;
		try {
			String httpContent = request.getContent();
			logger.info("zbvc request from " + request.getClientAddress() + ", " + request.getPath().getPath() + "\r\n");
			logger.info(httpContent);
			xmlMsg = XmlMessageParser.parseWSRequest(inputFactory, httpContent);
			xmlMsg.setMsgTime(receiveTime);
		} catch (IOException e) {
			errInfos = e.getMessage();
			e.printStackTrace();
		} catch (Exception e) {
			errInfos = e.getMessage();
			e.printStackTrace();
		}
		if(errInfos!=null){
			HttpAckHelper.errorAck(bodyPrintStream, xmlMsg, errInfos);
			return;
		}
		//验证能力是否授权
		HashSet<String> capabilities = PropertyRepository.getAuthorizationCapability();
		String capaName = MsgUtils.getCapabilityName(xmlMsg.getSCID());
		if(!capabilities.contains(capaName)){
			errInfos = "Not Authorization:" + capaName;
			HttpAckHelper.errorAck(bodyPrintStream, xmlMsg, errInfos);
			return;
		}
		//VC Client 连接失败
		if(VCClient.instance().getConnectionStatus()!=MMLConstants.VC_CONN_OK){
			errInfos = "VC Client is disconnection";
			HttpAckHelper.errorAck(bodyPrintStream, xmlMsg, errInfos);	
			return;		
		}		
		//add XML message into repository
		MMLSessionEntity sessionEntity = MMLSessionEntity.buildEntity(xmlMsg, bodyPrintStream);
		VCMsgRepository.offerXmlMsg(sessionEntity);
		LogMsgHelper.appendLogMsg(sessionEntity.getXmlMsg());
		
//		if (request.getPath().getPath().endsWith(tbChargePath)) {
//			return ;
//		}else if(request.getPath().getPath().endsWith(tbSignPath)){
//			return ;
//		}else{
//			logger.debug("request path is invalid:"	+ request.getPath().getPath()+ " , ignore this request.");
//		}
		
	}
	
	@Override
	public int sendRequest(CallParam callParam) {
		
		if (logger.isDebugEnabled()) {
			logger.debug(callParam.getSessionId()+ ", prepare forward request to TaoBao:"+ callParam.getToNode().getServerUrl());
		}
		
		return -1 ;
	}
	
	@Override
	public void addPersist(Node node) {
		// TODO Auto-generated method stub
	}
	@Override
	public void deletePersist(Node node) {
		// TODO Auto-generated method stub
	}
	@Override
	public Set<String> monitorConfKeys() {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public void onConfigUpdated(String updatedKey) {
		// TODO Auto-generated method stub
	}
	@Override
	public SGWChannel getSGWChannel() {
		return this.channel;
	}
	@Override
	public int getThreadPoolSize() {
		return executor.getPoolSize();
	}
	@Override
	public int getThreadPoolQueueSize() {
		return executor.getQueue().size();
	}
	@Override
	public int getThreadPoolActiveCount() {
		return executor.getActiveCount();
	}
	@Override
	public int getNodeSendQueueSize(String nodeHostId) {
		// TODO Auto-generated method stub
		return 0;
	}
	
	public static void main(String[] args){
		
		
		String xml = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:soap=\"http://www.chinatelecom.cn/SGW/SOAP\">";
		
		xml += "<soapenv:Header/>";
		xml += "<soapenv:Body>";
		xml += "<soap:SgwQueryReq>";
		xml += "<MID>zbcs@027.ctnbc-bon.net;13437322251411;4244</MID>";
		xml += "<UID>zbcs@027.ctnbc-bon.net</UID>";
		xml += "<PWD>E807F1FCF82D132F9BB018CA6738A19F</PWD>";
		xml += "<SCID>Auth.Access.mml@027.ctnbc-bon.net</SCID>";          
		xml += "<SIG></SIG>";
		xml += "<REPTAG>0</REPTAG>";
		xml += "<RSV1></RSV1>";
		xml += "<RSV2></RSV2>";
		xml += "<DATA><![CDATA[";
		xml += "<Service_Information>";
		xml += "<MSISDN>18907210066</MSISDN>";
		xml += "<NOTYPE>2</NOTYPE>";
		xml += "</Service_Information>]]>";
		//xml += "</DATA>";
		xml += "</soap:SgwQueryReq>";
		xml += "</soapenv:Body>";
		xml += "</soapenv:Envelope>";
		
		XmlMessage xmlMsg = null;
		try {
			xmlMsg = XmlMessageParser.parseWSRequest(inputFactory, xml);
		} catch (Exception e) {
			System.out.println(e.getMessage());
			System.out.println(e.getLocalizedMessage());
			
			//e.printStackTrace();
		}
		System.out.println(xmlMsg.getSCID());
		
//		SGWChannel channel = new SGWChannel();
//		channel.setUri("http://192.168.1.107:9999");
//		ZBVCChannel zbvcChannel = new ZBVCChannel(channel);
//		try {
//			zbvcChannel.start();
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
//		
//		try {
//			Thread.sleep(1000000);
//		} catch (InterruptedException e) {
//			e.printStackTrace();
//		}
		
		
	}
}
